package com.zcx.utils;

import com.huaban.analysis.jieba.JiebaSegmenter;
import com.huaban.analysis.jieba.SegToken;
import java.util.*;

public class SimHash {

    private JiebaSegmenter segmenter = new JiebaSegmenter(); // 分词
    private int bitNum = 64;
    private int hammingDistance = 3;// 汉明距离的衡量标准

    public SimHash() {
    }

    /**
     * 指定文本计算simhash值
     * 先通过对文本进行分词，然后计算每一个词的hsah值，然后组合为一个64位的simhash
     * @param content
     * @return Long
     */
    public String calSimhash(String content) {
        String filterContent = content.trim().replaceAll("\\p{Punct}|\\p{Space}", "");
        // 切词
        List<SegToken> segTokens = segmenter.process(filterContent, JiebaSegmenter.SegMode.SEARCH);

        System.out.println("获得的分词为：");
        for (SegToken segToken : segTokens) {
            System.out.print(segToken+ " ---");
        }
        System.out.println("");

        // 按照词语的hash值，计算simHashWeight(低位对齐)
        Integer[] weight = new Integer[bitNum];
        Arrays.fill(weight, 0);
        for (SegToken st : segTokens) {
            long wordHash = Murmur3.hash64(st.word.getBytes());
            for (int i = 0; i < bitNum; i++) {
                if (((wordHash >> i) & 1) == 1){
                    weight[i] += 1;
                } else {
                    weight[i] -= 1;
                }
            }
        }

        // 计算得到Simhash值
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bitNum; i++) {
            if (weight[i] > 0){
                sb.append(1);
            }
            else {
                sb.append(0);
            }
        }

        return sb.toString();
    }

    /**
     * 判断文本是否重复
     * @param content
     * @return
     */
    public boolean isDuplicate(String content,String other) {

        if(hamming(content,other) > hammingDistance){
            return false;
        }
        return true;
    }

    private int hamming(String s1, String s2) {

        int dis = 0;
        for (int i = 0; i < s1.length(); i++) {
            if (s1.charAt(i) != s2.charAt(i)) {
                dis++;
            }
        }
        return dis;
    }
}
